package com.ruicar.afs.cloud.afscase.risk.notice;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.afscase.approvemakelabel.entity.ApproveMakeLabel;
import com.ruicar.afs.cloud.afscase.approvemakelabel.service.ApproveMakeLabelService;
import com.ruicar.afs.cloud.afscase.approveprev.entity.CaseApprovePrevInfo;
import com.ruicar.afs.cloud.afscase.approveprev.service.CaseApprovePrevInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.entity.CaseApproveRecord;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfo;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkTaskPool;
import com.ruicar.afs.cloud.afscase.approvetask.service.CaseApproveRecordService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkTaskPoolService;
import com.ruicar.afs.cloud.afscase.common.step.StepParam;
import com.ruicar.afs.cloud.afscase.common.step.Steps;
import com.ruicar.afs.cloud.afscase.common.utils.Const;
import com.ruicar.afs.cloud.afscase.common.utils.DicUtils;
import com.ruicar.afs.cloud.afscase.common.utils.StepUtil;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.*;
import com.ruicar.afs.cloud.afscase.infomanagement.service.*;
import com.ruicar.afs.cloud.afscase.manuallabel.entity.ManualLabel;
import com.ruicar.afs.cloud.afscase.manuallabel.service.ManualLabelService;
import com.ruicar.afs.cloud.afscase.mq.approvesendinfo.service.ApproveInformInfoService;
import com.ruicar.afs.cloud.afscase.mq.sender.ApprovePrevSender;
import com.ruicar.afs.cloud.afscase.postloan.service.CaseRepayPlanService;
import com.ruicar.afs.cloud.afscase.postloan.vo.CaseRepayPlanVO;
import com.ruicar.afs.cloud.afscase.processor.enums.NormalSubmitType;
import com.ruicar.afs.cloud.afscase.remind.entity.CaseRemindDetail;
import com.ruicar.afs.cloud.afscase.risk.entity.*;
import com.ruicar.afs.cloud.afscase.risk.service.*;
import com.ruicar.afs.cloud.afscase.step.entity.CaseStepParam;
import com.ruicar.afs.cloud.afscase.step.service.CaseStepParamService;
import com.ruicar.afs.cloud.bizcommon.business.entity.FinCostDetails;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.modules.contract.enums.RepaymentStatusEnum;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.common.modules.contract.ContractMainInfoDto;
import com.ruicar.afs.cloud.common.modules.dto.mq.approveprev.ApprovePrevResultDto;
import com.ruicar.afs.cloud.common.mq.rabbit.message.AfsTransEntity;
import com.ruicar.afs.cloud.common.mq.rabbit.message.MqTransCode;
import com.ruicar.afs.cloud.components.datadicsync.DicHelper;
import com.ruicar.afs.cloud.components.datadicsync.dto.DicDataDto;
import com.ruicar.afs.cloud.image.entity.ComAttachmentFile;
import com.ruicar.afs.cloud.image.enums.AttachmentUniqueCodeEnum;
import com.ruicar.afs.cloud.image.service.ComAttaManageService;
import com.ruicar.afs.cloud.image.service.ComAttachmentFileService;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.TortoiseQueryBean;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.TortoiseResultNotice;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.notice.*;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.GwtExposureData;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoiseExposurePerson;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoiseExposureReq;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoiseFraudPushData;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.*;
import com.ruicar.afs.cloud.risk.api.notice.TortoiseNoticeProcessor;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.FLowGiveUpRequest;
import com.ruicar.afs.cloud.workflow.gwt.service.WorkflowService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author Peng Jinbo
 * @Date 2020/07/31 11:31
 */
@Service
@Slf4j
@AllArgsConstructor
public class TortoiseNoticeProcessorImpl implements TortoiseNoticeProcessor {

    /**
     * Case cust individual service
     */
    private CaseCustIndividualService caseCustIndividualService;
    /**
     * Case cust info service
     */
    private CaseCustInfoService caseCustInfoService;
    /**
     * Case base info service
     */
    private CaseBaseInfoService caseBaseInfoService;
    /**
     * Case cost info service
     */
    private CaseCostInfoService caseCostInfoService;
    /**
     * Case car info service
     */
    private CaseCarInfoService caseCarInfoService;
    /**
     * Case contract info service
     */
    private CaseContractInfoService caseContractInfoService;
    /**
     * Case cust contact service
     */
    private CaseCustContactService caseCustContactService;

    /**
     * Case tortoise prev service
     */
    private CaseTortoisePrevService caseTortoisePrevService;
    /**
     * Case tortoise fraud push service
     */
    private CaseTortoiseFraudPushService caseTortoiseFraudPushService;
    /**
     * Case tortoise decision hand service
     */
    private CaseTortoiseDecisionHandService caseTortoiseDecisionHandService;
    /**
     * Case tortoise apply service
     */
    private CaseTortoiseApplyService caseTortoiseApplyService;
    /**
     * Case tortoise fraud hand service
     */
    private CaseTortoiseFraudHandService caseTortoiseFraudHandService;
    /**
     * Case approve prev info service
     */
    private CaseApprovePrevInfoService caseApprovePrevInfoService;
    /**
     * Approve make label service
     */
    private ApproveMakeLabelService approveMakeLabelService;
    /**
     * Manual label service
     */
    private ManualLabelService manualLabelService;

    /**
     * Approve prev sender
     */
    private ApprovePrevSender approvePrevSender;


    private CaseRepayPlanService caseRepayPlanService;

    private ComAttaManageService comAttaManageService;

    private ComAttachmentFileService comAttachmentFileService;

    private ApproveInformInfoService approveInformInfoService;

    private DataQueryService dataQueryService;

    private CaseStepParamService caseStepParamService;

    private WorkProcessScheduleInfoService workProcessScheduleInfoService;

    private WorkTaskPoolService workTaskPoolService;

    private WorkflowService workflowService;

    private CaseApproveRecordService caseApproveRecordService;

    private CaseTortoiseService caseTortoiseService;

    private CaseTortoiseExposureExceptService caseTortoiseExposureExceptService;

    /**
     * Author Peng Jinbo
     * Normal apply *
     *
     * @param resultNotice result notice
     */
    @Transactional
    public void normalApply(TortoiseResultNotice<TortoiseApplyNoticeInfo> resultNotice) {
        log.info("玄武正式进件返回通知:{}", resultNotice);
        if (Objects.nonNull(resultNotice)) {
            TortoiseApplyNoticeInfo noticeInfo = resultNotice.getNoticeInfo();
            CaseTortoiseApply apply = caseTortoiseApplyService.getById(resultNotice.getSerialNumber());
            if (resultNotice.isErr()) {
                CaseRemindDetail remind = new CaseRemindDetail();
                remind.setOperationType(WhetherEnum.YES.getCode());
                remind.setRemindType(AfsEnumUtil.key(NormalSubmitType.SEND_BACK_TO_DEALER));
                remind.setRemindContent(resultNotice.getErrMsg());
                remind.setApplyNo(resultNotice.getApplyNo());
                remind.setNoticeType(apply.getType());
                autoRefuseBeforeWorkflow(resultNotice,remind,BusinessStateInEnum.DRAFT);
            } else {
                apply.setNoticeDate(resultNotice.getNoticeDate());
                apply.setDecisionResult(noticeInfo.getResult());
                apply.setPledgeFlag(noticeInfo.getPledgeFlag());
                apply.setScore(noticeInfo.getScore());
                apply.setScoreLevel(noticeInfo.getScoreLevel());
                apply.setFraudResult(noticeInfo.getAntiFraudResult());
                apply.setFraudResultScore(noticeInfo.getAntiFraudScore());
                apply.setCustomerCreditScore(noticeInfo.getCustomerScore());
                apply.setSponsorCreditScore(noticeInfo.getSponsorScore());
                apply.setBondCreditScore(noticeInfo.getBondScore());
                final StringBuffer tags = new StringBuffer();
                if (CollectionUtil.isNotEmpty(noticeInfo.getTagList())) {
                    noticeInfo.getTagList().forEach(tag -> tags.append(tag).append(","));
                    if(tags.toString().endsWith(",")){
                        tags.substring(0, tags.length() - 1);
                    }

                    List<ManualLabel> labels = manualLabelService.list(
                            Wrappers.<ManualLabel>lambdaQuery()
                                    .in(ManualLabel::getLabelNo, noticeInfo.getTagList())
                    );
                    approveMakeLabelService.remove(
                            Wrappers.<ApproveMakeLabel>lambdaQuery()
                                    .eq(ApproveMakeLabel::getApplyNo, apply.getApplyNo())
                                    .eq(ApproveMakeLabel::getLabelClassification, AfsEnumUtil.key(LabelClassEnum.TORTOISE))
                    );
                    // 打标签
                    List<ApproveMakeLabel> caseLabelList = new ArrayList<>(labels.size());
                    for (ManualLabel label : labels) {
                        ApproveMakeLabel caseLabel = new ApproveMakeLabel();
                        caseLabel.setApplyNo(apply.getApplyNo());
                        caseLabel.setLabelId(label.getId());
                        caseLabel.setLabelPattern(LabelWayEnum.AUTOMATIC.getCode());
                        caseLabel.setLabelName(label.getLabelName());
                        caseLabel.setLabelPhase(label.getLabelPhase());
                        caseLabel.setLabelColor(label.getLabelColor());
                        caseLabel.setLabelType(label.getLabelType());
                        caseLabel.setLabelLocation(label.getLabelLocation());
                        caseLabel.setLabelSort(label.getLabelSort());
                        caseLabel.setLabelClassification(label.getLabelClassification());
                        caseLabelList.add(caseLabel);
                    }
                    approveMakeLabelService.saveBatch(caseLabelList);
                }
                apply.setTags(tags.toString());
                caseTortoiseApplyService.updateById(apply);

                CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                        Wrappers.<CaseBaseInfo>lambdaQuery()
                                .eq(CaseBaseInfo::getApplyNo, apply.getApplyNo())
                );
                baseInfo.setTortoiseApplyExecute(AfsEnumUtil.key(TortoiseApplyExecuteEnum.DONE));
                caseBaseInfoService.updateById(baseInfo);

                CaseStepParam caseStepParam = caseStepParamService.getLast(apply.getApplyNo(),StepSceneEnum.APPROVE);
                if(caseStepParam.getScene() == StepSceneEnum.APPROVE){
                    if(noticeInfo.isAutoReject()) { // 是否自动拒绝
                        if(! WhetherEnum.YES.getCode().equals(caseStepParam.getReturnSubmit())){
                            CaseRemindDetail remind = new CaseRemindDetail();
                            remind.setOperationType(WhetherEnum.YES.getCode());
                            remind.setRemindType(AfsEnumUtil.key(NormalSubmitType.SUGGEST_REJECT_FINAL));
                            remind.setRemindContent(AfsEnumUtil.desc(ApproveRefuseReasonEnum.AUTO_SYSTEM_RISK_NOT_SUPPORT));
                            remind.setApplyNo(apply.getApplyNo());
                            saveAutoRejectRecord(remind.getApplyNo(),"");
                            autoRefuseBeforeWorkflow(resultNotice,remind,BusinessStateInEnum.REJECT);
                        } else {
                            autoRefuseAfterWorkflow(caseStepParam);
                        }
                        // 流程自动拒绝后调用玄武反欺诈，同步案件信息
                        caseTortoiseService.safeSignalFraudHand(baseInfo.getApplyNo(), GwtTortoiseAntiFraudCallStep.AFTER_FINALLY_APPROVE_END);
                    }else{
                        // 玄武开关关闭后才可能手工调用，此时不走系统剩余操作
                        if(StrUtil.equals(WhetherEnum.YES.getCode(),apply.getHandInvoke())){
                            return;
                        }
                        StepUtil.prevSteps(StepParam.builder()
                                .applyNo(baseInfo.getApplyNo())
                                .baseInfo(baseInfo)
                                .stageId(caseStepParam.getStageId())
                                .processTypeEnum(caseStepParam.getFlowType())
                                .returnSubmit(WhetherEnum.YES.getCode().equals(caseStepParam.getReturnSubmit()))
                                .tortoiseNoticeBack(true)
                                .leaveMessage(caseStepParam.getLeaveMessage())
                                .build());
                    }
                }
            }
        }
    }

    /**
    * @Description 流程发起前反欺诈高风险自动拒绝
    * @Author Peng_Jinbo
    * @Date 2020/9/1 16:23
    */
    @Transactional
    public void autoRefuseBeforeWorkflow(TortoiseResultNotice<TortoiseApplyNoticeInfo> resultNotice,CaseRemindDetail remind,BusinessStateInEnum businessStateInEnum){
        approveInformInfoService.submitLeaveMessage(remind);
        CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                Wrappers.<CaseBaseInfo>lambdaQuery()
                        .eq(CaseBaseInfo::getApplyNo, resultNotice.getApplyNo())
        );
        baseInfo.setWorkflowPrevStep(Steps.END_STEP == baseInfo.getWorkflowPrevStep()
                ? Steps.END_STEP : baseInfo.getWorkflowPrevStep() - 1);
        baseInfo.setTortoiseApplyExecute(AfsEnumUtil.key(TortoiseApplyExecuteEnum.DONE));
        baseInfo.setBusinessStateIn(AfsEnumUtil.key(businessStateInEnum));
        baseInfo.setRejectReason(AfsEnumUtil.key(ApproveRefuseReasonEnum.AUTO_SYSTEM_RISK_NOT_SUPPORT));
        caseBaseInfoService.updateById(baseInfo);
    }

    /**
    * @Description 流程发起后反欺诈高风险自动拒绝
    * @Author Peng_Jinbo
    * @Date 2020/9/1 16:26
    */
    @Transactional
    public void autoRefuseAfterWorkflow(CaseStepParam stepParam){
        Assert.isTrue(StrUtil.isNotBlank(stepParam.getStageId()),"反欺诈高风险自动拒绝失败，流程编号为空");
        WorkProcessScheduleInfo info = workProcessScheduleInfoService.getById(stepParam.getStageId());
        if(Objects.nonNull(info)){
            log.info("高风险命中，流程自动拒绝 start");
            // 废弃流程
            FLowGiveUpRequest fLowGiveUpRequest = new FLowGiveUpRequest();
            fLowGiveUpRequest.setFlowInstanceId(info.getStageId());
            fLowGiveUpRequest.setReason(AfsEnumUtil.key(ApproveRefuseReasonEnum.AUTO_SYSTEM_RISK_NOT_SUPPORT));
            workflowService.flowGiveUp(fLowGiveUpRequest);

            // 删除目前存在的任务
            workTaskPoolService.remove(
                    Wrappers.<WorkTaskPool>lambdaQuery()
                        .eq(WorkTaskPool::getStageId,info.getId().toString())
            );

            // 案件状态置为拒绝
            caseBaseInfoService.update(
                    Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo,info.getApplyNo())
                        .set(CaseBaseInfo::getRejectReason,AfsEnumUtil.key(ApproveRefuseReasonEnum.AUTO_SYSTEM_RISK_NOT_SUPPORT))
                        .set(CaseBaseInfo::getBusinessStateIn,AfsEnumUtil.key(BusinessStateInEnum.REJECT))
            );

            // 通知进件端
            CaseApproveRecord record = saveAutoRejectRecord(info.getApplyNo(),info.getStageId());
            approveInformInfoService.submitApprovalNotic(record);
            log.info("高风险命中，流程自动拒绝 end");
        }else{
            log.warn("流程实例信息不存在，自动拒绝失败. {}",stepParam);
        }
    }

    private CaseApproveRecord saveAutoRejectRecord(String applyNo,String stageId){
        CaseApproveRecord record = new CaseApproveRecord();
        record.setApplyNo(applyNo);
        record.setStageId(stageId);
        record.setUseScene(UseSceneEnum.APPROVE.getValue());
        record.setApproveSuggest(AfsEnumUtil.key(NormalSubmitType.SUGGEST_REJECT_FINAL));
        record.setApproveSuggestName(AfsEnumUtil.desc(NormalSubmitType.SUGGEST_REJECT_FINAL));
        record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
        record.setApproveRemark("客户资质与我司风险政策不符");
        record.setApproveEndTime(new Date());
        record.setApproveStartTime(new Date());
        record.setDisposeStaff("系统");
        caseApproveRecordService.save(record);
        return record;
    }

    /**
     * Author Peng Jinbo
     * Prev approve *
     *
     * @param resultNotice result notice
     */
    public void prevApprove(TortoiseResultNotice<TortoisePrevApproveNoticeInfo> resultNotice) {
        log.info("玄武预审批进件返回通知 : {},{}",resultNotice.getSerialNumber(), resultNotice);
        if (Objects.nonNull(resultNotice)) {
            TortoisePrevApproveNoticeInfo noticeInfo = resultNotice.getNoticeInfo();
            CaseTortoisePrev prev = caseTortoisePrevService.getById(resultNotice.getSerialNumber());
            prev.setNoticeDate(resultNotice.getNoticeDate());
            prev.setPriceLimit(noticeInfo.getPriceLimit());
            prev.setRejectReason(noticeInfo.getRefuseReason());
            prev.setResult(noticeInfo.getResult());
            prev.setType(noticeInfo.getType());
            prev.setApproveDate(noticeInfo.getPrevApproveDate());
            prev.setRejectReason(noticeInfo.getRefuseReason());
            caseTortoisePrevService.updateById(prev);
            if(StrUtil.isNotBlank(prev.getPrevId())) {
                CaseApprovePrevInfo prevInfo = caseApprovePrevInfoService.getById(prev.getPrevId());
                if(Objects.nonNull(prevInfo)){
                    prevInfo.setReportId(prev.getId().toString());
                    prevInfo.setRefuseReason(prev.getRejectReason());
                    prevInfo.setApproveDate(prev.getApproveDate());
                    prevInfo.setApplyStatus(prev.getResult());
                    caseApprovePrevInfoService.updateById(prevInfo);

                    // 结果通知进件端
                    ApprovePrevResultDto prevResultDto = ApprovePrevResultDto.builder()
                            .applyId(prevInfo.getApplyId())
                            .approveDate(prev.getApproveDate())
                            .approveResult(prev.getResult())
                            .refuseReason(prev.getRejectReason())
                            .priceLimit(prev.getPriceLimit())
                            .build();
                    AfsTransEntity<ApprovePrevResultDto> resultTransEntity = new AfsTransEntity();
                    resultTransEntity.setTransCode(MqTransCode.AFS_POS_CASE_APPLY_CTM_APPROVE_PREV_NOTICE);
                    resultTransEntity.setData(prevResultDto);
                    approvePrevSender.sendPrevResultToApplySystem(resultTransEntity);
                }
            }
            log.info("玄武预审批进件返回通知处理完毕 : {}", resultNotice.getSerialNumber());
        }
    }

    /**
     * Author Peng Jinbo
     * Fraud push *
     *
     * @param resultNotice result notice
     */
    public void fraudPush(TortoiseResultNotice<TortoiseFraudPushNoticeInfo> resultNotice) {
        log.info("玄武欺诈信息推送返回通知 : {},{}",resultNotice.getSerialNumber(), resultNotice);
        if (Objects.nonNull(resultNotice)) {
            TortoiseFraudPushNoticeInfo noticeInfo = resultNotice.getNoticeInfo();
            CaseTortoiseFraudPush fraudPush = caseTortoiseFraudPushService.getById(resultNotice.getSerialNumber());
            fraudPush.setNoticeDate(resultNotice.getNoticeDate());
            fraudPush.setPushResult(noticeInfo.getResult());
            caseTortoiseFraudPushService.updateById(fraudPush);
            log.info("玄武欺诈信息推送返回通知接收完毕:{}", resultNotice.getSerialNumber());
        }
    }

    /**
     * Author Peng Jinbo
     * Hand fraud *
     *
     * @param resultNotice result notice
     */
    public void handFraud(TortoiseResultNotice<TortoiseHandFraudNoticeInfo> resultNotice) {
        log.info("玄武手动触发反欺诈返回通知:{},{}",resultNotice.getSerialNumber(), resultNotice);
        if (Objects.nonNull(resultNotice)) {
            TortoiseHandFraudNoticeInfo noticeInfo = resultNotice.getNoticeInfo();
            CaseTortoiseFraudHand fraudHand = caseTortoiseFraudHandService.getById(resultNotice.getSerialNumber());
            fraudHand.setNoticeDate(resultNotice.getNoticeDate());
            fraudHand.setFraudResult(noticeInfo.getResult());
            fraudHand.setFraudScore(noticeInfo.getScore());
            caseTortoiseFraudHandService.updateById(fraudHand);
            log.info("玄武手动触发反欺诈返回通知接收完毕 : {} ",resultNotice.getSerialNumber());
        }
    }

    /**
     * Author Peng Jinbo
     * Hand decision *
     *
     * @param resultNotice result notice
     */
    public void handDecision(TortoiseResultNotice<TortoiseHandDecisionNoticeInfo> resultNotice) {
        log.info("玄武手动调用决策引擎返回通知:{},{}", resultNotice.getSerialNumber(),resultNotice);
        if (Objects.nonNull(resultNotice)) {
            TortoiseHandDecisionNoticeInfo noticeInfo = resultNotice.getNoticeInfo();
            CaseTortoiseDecisionHand decisionHand = caseTortoiseDecisionHandService.getById(resultNotice.getSerialNumber());
            decisionHand.setNoticeDate(resultNotice.getNoticeDate());
            decisionHand.setDecisionResult(noticeInfo.getResult());
            decisionHand.setPledgeFlag(noticeInfo.getPledgeFlag());
            decisionHand.setScore(noticeInfo.getScore());
            decisionHand.setScoreLevel(noticeInfo.getScoreLevel());
            caseTortoiseDecisionHandService.updateById(decisionHand);
            log.info("玄武手动调用决策引擎返回通知接收完毕 : {}",resultNotice.getSerialNumber());
        }
    }

    /**
     * @param applyNo apply no
     * @return the image
     * @Author Peng Jinbo Gets image *
     */
    @Override
    public String getImage(String applyNo) {
        try {
            log.info("面签照片获取 ==> {}",applyNo);
            ComAttachmentFile comAttachmentFile= comAttaManageService.getFile(AttachmentUniqueCodeEnum.ORDER_APPLY_FACE_PHOTO.getCode(),applyNo);
            String imgStr="";
            if(!ObjectUtils.isEmpty(comAttachmentFile)){
                byte[] fileBytes=comAttachmentFileService.downloadFileBytes(comAttachmentFile.getFileId());
                if(fileBytes!=null){
                    imgStr = Base64.getEncoder().encodeToString(fileBytes);
                }else{
                    log.error("{}面签照片=>{}下载失败！",applyNo,comAttachmentFile.getFileId());
                }
            }else{
                log.error("{}面签照片获取为找到相应面签图片信息！",applyNo);
            }
            return imgStr;
        } catch (Exception e) {
            log.error("面签照片获取",e);
            throw new AfsBaseException("面签照片获取失败");
        }
    }

    /**
     * @Desciption
     *  每个TortoiseExposurePerson对象代表当前所查询敞口单的人员信息(主借人/共借人/担保人/紧急联系人)
     *  每种类型人员关联出来的单个申请编号相关信息为一条数据
     *
     *   1. 比如当前查重人员为主借人customerA，此时关联到申请编号为applyNo-A的案件主借人身份证号/主借人电话/共借人公司信息
     *      等等情况，此时仅返回一条数据，由customerA关联出来的applyNo-A的相关案件信息。多次关联在查重方式字段内体现
     *
     *   2. 如果当前单的共借人信息customerB,同时也关联到申请编号为applyNo-A的案件共借人信息/共借人电话，等等情况，
     *      那么当前会重新生成一条customerB与applyNo-A的关联数据。
     *
     * @param exposureReq exposure req
     * @return the exposure data
     * @Author Peng Jinbo Gets exposure data *
     */
    @Override
    public List<GwtExposureData> getExposureData(TortoiseExposureReq exposureReq) {
        log.info("敞口信息获取 ==> {}",exposureReq);
        return getExposureDataList(exposureReq);
    }

    /**
     * @param exposureReq exposure req
     * @return the exposure data list
     * @Author Peng Jinbo Gets exposure data list *
     */
    private List<GwtExposureData> getExposureDataList(TortoiseExposureReq exposureReq) {
        Map<String, GwtExposureData> gwtExposureDataMap = new HashMap<>();
        exposureReq.getPersonList().forEach(person -> {
            gwtExposureDataMap.put(exposureReq.getApplyNo() + "-" + person.getUserId(), null);
        });
        for (TortoiseExposurePerson exposurePerson : exposureReq.getPersonList()) {
            // 根据手机号查重
            checkPhone(exposurePerson, gwtExposureDataMap);
            // 根据身份证号查重
            checkCard(exposurePerson, gwtExposureDataMap);
            // 根据单位查重
            checkCompany(exposurePerson, gwtExposureDataMap);
            // 检查预审批记录
            checkPrevApprove(exposurePerson, gwtExposureDataMap);
        }
        return gwtExposureDataMap.values().stream().filter(
                exposureData ->
                        Objects.nonNull(exposureData) && !StrUtil.equals(exposureData.getApplyNo(), exposureReq.getApplyNo())
        ).collect(Collectors.toList());
    }

    /**
     * Author Peng Jinbo
     * Check prev approve *
     * 查重预审信息
     *
     * @param exposurePerson     exposure person
     * @param gwtExposureDataMap gwt exposure data map
     */
    private void checkPrevApprove(TortoiseExposurePerson exposurePerson, Map<String, GwtExposureData> gwtExposureDataMap) {
        if(StrUtil.isNotBlank(exposurePerson.getCard())) {
            List<CaseApprovePrevInfo> byCardList = caseApprovePrevInfoService.list(
                    Wrappers.<CaseApprovePrevInfo>lambdaQuery()
                            .eq(CaseApprovePrevInfo::getCertNo, exposurePerson.getCard())
            );

            if (CollectionUtil.isNotEmpty(byCardList)) {
                for (CaseApprovePrevInfo prevInfo : byCardList) {
                    addPrev(gwtExposureDataMap, GwtTortoiseExposureType.CARD, exposurePerson, prevInfo);
                }
            }
        }
        if(StrUtil.isNotBlank(exposurePerson.getPhone())) {
            List<CaseApprovePrevInfo> byPhoneList = caseApprovePrevInfoService.list(
                    Wrappers.<CaseApprovePrevInfo>lambdaQuery()
                            .eq(CaseApprovePrevInfo::getTelPhone, exposurePerson.getPhone())
            );

            if (CollectionUtil.isNotEmpty(byPhoneList)) {
                for (CaseApprovePrevInfo prevInfo : byPhoneList) {
                    addPrev(gwtExposureDataMap, GwtTortoiseExposureType.PHONE, exposurePerson, prevInfo);
                }
            }
        }
    }

    /**
     * Author Peng Jinbo
     * Add prev *
     *
     * @param gwtExposureDataMap gwt exposure data map
     * @param type               type
     * @param exposurePerson     exposure person
     * @param prevInfo           prev info
     */
    private void addPrev(Map<String, GwtExposureData> gwtExposureDataMap, GwtTortoiseExposureType type,
                         TortoiseExposurePerson exposurePerson,CaseApprovePrevInfo prevInfo) {
        int caseBaseCount = caseBaseInfoService.count(
                Wrappers.<CaseBaseInfo>lambdaQuery()
                    .eq(CaseBaseInfo::getApplyNo,prevInfo.getApplyNo())
        );
        // 预审已转正式进件的数据除外
        if(caseBaseCount > 0){
            return;
        }
        String key = exposurePerson.getUserId() + "-" + prevInfo.getApplyNo();
        String checkRepeatType = AfsEnumUtil.desc(CustRoleEnum.MIANCUST) + "." + AfsEnumUtil.desc(type);
        if(gwtExposureDataMap.containsKey(key)
                && Objects.nonNull(gwtExposureDataMap.get(key))){
            GwtExposureData data = gwtExposureDataMap.get(key);
            data.setCheckRepeatType(data.getCheckRepeatType() + ";" + checkRepeatType);
            return;
        }
        String applyStatus = prevInfo.getApplyStatus();
        if(StrUtil.isBlank(applyStatus)){
            applyStatus = "已提交";
        }else if(StrUtil.equals(WhetherEnum.YES.getCode(),applyStatus)){
            applyStatus = AfsEnumUtil.desc(GwtTortoisePrevResult.AGREE);
        }else if(StrUtil.equals(WhetherEnum.NO.getCode(),applyStatus)){
            applyStatus = AfsEnumUtil.desc(GwtTortoisePrevResult.REFUSE);
        }else{
            applyStatus = AfsEnumUtil.desc(AfsEnumUtil.getEnum(applyStatus,GwtTortoisePrevResult.class));
        }
        GwtExposureData exposureData = GwtExposureData.builder()
                .applyNo(prevInfo.getApplyNo())
                .mainId(prevInfo.getId().toString())
                .applyDate(prevInfo.getApplyDate())
                .customerName(prevInfo.getCustName())
                .dataSource("BOSS-预审")
                .checkRepeatType(checkRepeatType)
                .type(exposurePerson.getType())
                .rejectReason(prevInfo.getRefuseReason())
                .userId(exposurePerson.getUserId())
                .createTime(prevInfo.getCreateTime())
                .applyDate(prevInfo.getCreateTime())
                .businessStatusName(applyStatus)
                .build();
        gwtExposureDataMap.put(key, exposureData);
    }

    /**
     * Author Peng Jinbo
     * Check company *
     * 根据单位名称查重
     *
     * @param exposurePerson     exposure person
     * @param gwtExposureDataMap gwt exposure data map
     */
    private void checkCompany(TortoiseExposurePerson exposurePerson, Map<String, GwtExposureData> gwtExposureDataMap) {
        if(caseTortoiseExposureExceptService.exists(exposurePerson.getCompany())) return;
        List<CaseCustIndividual> individualList = caseCustIndividualService.list(
                Wrappers.<CaseCustIndividual>lambdaQuery()
                    .eq(CaseCustIndividual::getUnitName,exposurePerson.getCompany())
        );
        List<Long> custIdList = new ArrayList<>();
        for (CaseCustIndividual caseCustIndividual : individualList) {
            if(!custIdList.contains(caseCustIndividual.getCustId().toString())){
                custIdList.add(caseCustIndividual.getCustId());
            }
        }
        if(CollectionUtil.isNotEmpty(custIdList)) {
            List<CaseCustInfo> custInfoList = caseCustInfoService.list(
                    Wrappers.<CaseCustInfo>lambdaQuery()
                            .in(CaseCustInfo::getId, custIdList)
            );
            if (CollectionUtil.isNotEmpty(custInfoList)) {
                for (CaseCustInfo custInfo : custInfoList) {
                    add(gwtExposureDataMap, custInfo.getApplyNo(), GwtTortoiseExposureType.COMPANY, exposurePerson,AfsEnumUtil.desc(AfsEnumUtil.getEnum(custInfo.getCustRole(),CustRoleEnum.class)));
                }
            }
        }
    }

    /**
     * Author Peng Jinbo
     * Check card *
     * 根据身份证号查重
     *
     * @param exposurePerson     exposure person
     * @param gwtExposureDataMap gwt exposure data map
     */
    private void checkCard(TortoiseExposurePerson exposurePerson, Map<String, GwtExposureData> gwtExposureDataMap) {
        if(StrUtil.isBlank(exposurePerson.getCard())) return;
        List<CaseCustInfo> custInfoList = caseCustInfoService.list(
                Wrappers.<CaseCustInfo>lambdaQuery()
                        .eq(CaseCustInfo::getCertNo, exposurePerson.getCard())
        );
        if (CollectionUtil.isNotEmpty(custInfoList)) {
            for (CaseCustInfo custInfo : custInfoList) {
                add(gwtExposureDataMap, custInfo.getApplyNo(), GwtTortoiseExposureType.CARD, exposurePerson,AfsEnumUtil.desc(AfsEnumUtil.getEnum(custInfo.getCustRole(),CustRoleEnum.class)));
            }
        }
        List<CaseCustContact> custContactList = caseCustContactService.list(
                Wrappers.<CaseCustContact>lambdaQuery()
                        .eq(CaseCustContact::getCertNo, exposurePerson.getCard())
        );

        if (CollectionUtil.isNotEmpty(custContactList)) {
            for (CaseCustContact custContact : custContactList) {
                add(gwtExposureDataMap, custContact.getApplyNo(), GwtTortoiseExposureType.CARD, exposurePerson,"紧急联系人");
            }
        }

    }

    /**
     * Author Peng Jinbo
     * Check phone *
     * 根据电话查重
     *
     * @param exposurePerson     exposure person
     * @param gwtExposureDataMap gwt exposure data map
     */
    private void checkPhone(TortoiseExposurePerson exposurePerson, Map<String, GwtExposureData> gwtExposureDataMap) {
        if(StrUtil.isBlank(exposurePerson.getPhone())) return;
        List<CaseCustInfo> custInfoList = caseCustInfoService.list(
                Wrappers.<CaseCustInfo>lambdaQuery()
                        .eq(CaseCustInfo::getTelPhone, exposurePerson.getPhone())
        );
        if (CollectionUtil.isNotEmpty(custInfoList)) {
            for (CaseCustInfo custInfo : custInfoList) {
                add(gwtExposureDataMap, custInfo.getApplyNo(), GwtTortoiseExposureType.PHONE, exposurePerson,AfsEnumUtil.desc(AfsEnumUtil.getEnum(custInfo.getCustRole(),CustRoleEnum.class)));
            }
        }
        List<CaseCustContact> custContactList = caseCustContactService.list(
                Wrappers.<CaseCustContact>lambdaQuery()
                        .eq(CaseCustContact::getTelPhone, exposurePerson.getPhone())
        );
        if (CollectionUtil.isNotEmpty(custContactList)) {
            for (CaseCustContact custContact : custContactList) {
                add(gwtExposureDataMap, custContact.getApplyNo(), GwtTortoiseExposureType.PHONE, exposurePerson,"紧急联系人");
            }
        }
    }

    /**
     * Author Peng Jinbo
     * Add *
     * 将已获取的关联敞口数据放入返回集合中
     *
     * @param gwtExposureDataMap        gwt exposure data map
     * @param applyNo                   apply no
     * @param type                      type
     * @param exposurePerson            exposure person
     * @param checkResultDutyPersonType check result duty person type
     */
    private void add(Map<String, GwtExposureData> gwtExposureDataMap, String applyNo, GwtTortoiseExposureType type,
                     TortoiseExposurePerson exposurePerson,String checkResultDutyPersonType) {
        String checkRepeatType = checkResultDutyPersonType + "." + AfsEnumUtil.desc(type);
        // 如果已存在敞口关联单，则将当前查重原因追加至关联单查重原因
        String key = applyNo + "-" + exposurePerson.getUserId();
        if (gwtExposureDataMap.containsKey(key) && Objects.nonNull(gwtExposureDataMap.get(key))) {
            GwtExposureData exposureData = gwtExposureDataMap.get(key);
            if(exposureData.getCheckRepeatType().indexOf(checkRepeatType) == -1) {
                exposureData.setCheckRepeatType(exposureData.getCheckRepeatType() + ";" + checkRepeatType);
            }
            return;
        }

        // 草稿案件不作为敞开关联单返回
        CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                Wrappers.<CaseBaseInfo>lambdaQuery()
                        .eq(CaseBaseInfo::getApplyNo, applyNo)
        );
        if(Objects.isNull(baseInfo) ||
                StrUtil.equals(AfsEnumUtil.key(BusinessStateInEnum.DRAFT),baseInfo.getBusinessStateIn())) return;

        CaseCustInfo custInfo = caseCustInfoService.getOne(
                Wrappers.<CaseCustInfo>lambdaQuery()
                        .eq(CaseCustInfo::getApplyNo, applyNo)
                        .eq(CaseCustInfo::getCustRole, CustRoleEnum.MIANCUST.getCode())
        );

        FinCostDetails costInfo = caseCostInfoService.getOne(
                Wrappers.<FinCostDetails>lambdaQuery()
                        .eq(FinCostDetails::getApplyNo, applyNo)
                        .eq(FinCostDetails::getCostType, CostTypeEnum.CARAMT.getCode())
        );

        CaseCarInfo carInfo = caseCarInfoService.getOne(
                Wrappers.<CaseCarInfo>lambdaQuery()
                        .eq(CaseCarInfo::getApplyNo, applyNo)
        );

        CaseContractInfo contract = caseContractInfoService.list(
                Wrappers.<CaseContractInfo>lambdaQuery()
                        .eq(CaseContractInfo::getApplyNo, applyNo)
        ).stream().findAny().orElse(new CaseContractInfo());

        Map<String, List<DicDataDto>> rejectReasonDic = DicHelper.getDicMaps("suggestRejectF");

        String caseStatus = StrUtil.isNotBlank(baseInfo.getBusinessStateIn())
                ? AfsEnumUtil.desc(AfsEnumUtil.getEnum(baseInfo.getBusinessStateIn(), BusinessStateInEnum.class)) : "";

        String contractStatus = "";
        if (StrUtil.isNotBlank(contract.getApplyStatus())) {
            ContractStatusEnum applyStatusEnum = contract.getContractStatus();
            if (Objects.nonNull(applyStatusEnum)) {
                contractStatus = applyStatusEnum.getDesc();
            }
        }

        List<CaseRepayPlanVO> repaymentPlanDTOList = caseRepayPlanService.listRepayPlans(applyNo);
        BigDecimal repaySum = BigDecimal.ZERO;
        if(CollectionUtil.isNotEmpty(repaymentPlanDTOList)){
            for (CaseRepayPlanVO plan : repaymentPlanDTOList) {
                if(RepaymentStatusEnum.REPAID == plan.getStatus())
                repaySum = repaySum.add(plan.getReceivablePrinciple());
            }
        }

        StringBuffer contractNoArrStr = new StringBuffer();
        StringBuffer contractStatusArrStr = new StringBuffer();
        List<ContractMainInfoDto> contractDtoList = caseRepayPlanService.listContractInfo(applyNo);
        if(CollectionUtil.isNotEmpty(contractDtoList)){
            for (int i = 0; i < contractDtoList.size(); i++) {
                ContractMainInfoDto contractMainInfoDto = contractDtoList.get(i);
                contractNoArrStr.append(Convert.toStr(contractMainInfoDto.getContractNo(),""));
                String contractRepayStatus = "";
                if(Objects.nonNull(contractMainInfoDto.getContractStatus())){
                    switch (contractMainInfoDto.getContractStatus()){
                        case contractCancel:
                            contractRepayStatus = "Flat Cancel"; // 合同取消
                            break;
                        case contractEffective:
                            contractRepayStatus = "正常"; // 合同生效 正常情况
                            break;
                        default:
                            contractRepayStatus = contractMainInfoDto.getContractStatus().getDesc();
                            break;
                    }
                }
                contractStatusArrStr.append(contractRepayStatus);
                if(i < contractDtoList.size()-1){
                    contractNoArrStr.append(",");
                    contractStatusArrStr.append(",");
                }
            }
        }

        GwtExposureData exposureData = GwtExposureData.builder()
                .userId(exposurePerson.getUserId())
                .mainId(Convert.toStr(baseInfo.getId()))
                .applyNo(baseInfo.getApplyNo())
                .applyDate(baseInfo.getPassFirstDate())
                .brandName(carInfo.getBrandName())
                .assetCost(costInfo.getContractAmt())
                .businessStatusName(caseStatus + " -> " + contractStatus)
                .customerName( custInfo.getCustName())
                .loanPeriod(Objects.nonNull(costInfo) ? Convert.toStr(costInfo.getLoanTerm()) : "")
                .loanMoney(baseInfo.getLoanAmtRepeat())
                .repayMoney(repaySum)
                .checkRepeatType(checkRepeatType)
                .dataSource(Const.TORTOISE_EXPOSURE_DATA_SOURCE)
                .rejectReason(DicUtils.translate(baseInfo.getRejectReason(), rejectReasonDic))
                .createTime(baseInfo.getCreateTime())
                .type(exposurePerson.getType())
                .contractNo(contractNoArrStr.toString())
                .repayStatus(contractStatusArrStr.toString())
                .build();
        gwtExposureDataMap.put(key, exposureData);
    }

    public TortoiseQueryBean getData(String mainId,String scene) {
        TortoiseQueryBean queryBean = new TortoiseQueryBean();
        if (StrUtil.isNotBlank(scene) && StrUtil.isNotBlank(mainId)) {
            GwtTortoiseScene sceneEnum = (GwtTortoiseScene) AfsEnumUtil.getEnum(scene, GwtTortoiseScene.class);
            if (GwtTortoiseScene.NORMAL_APPLY == sceneEnum
                    || GwtTortoiseScene.HAND_ANTI_FRAUD_INVOKE == sceneEnum
                    || GwtTortoiseScene.HAND_DECISION_INVOKE == sceneEnum) {
                CaseBaseInfo caseBaseInfo = caseBaseInfoService.getById(mainId);
                queryBean = dataQueryService.getApplyData(caseBaseInfo.getApplyNo());
            } else if (GwtTortoiseScene.PREV_APPROVE == sceneEnum) {
                CaseApprovePrevInfo prev = caseApprovePrevInfoService.getById(mainId);
                if (Objects.nonNull(prev)) {
                    queryBean = dataQueryService.queryPrev(prev);
                }
            } else if (GwtTortoiseScene.FRAUD_PUSH == sceneEnum){
                CaseBaseInfo caseBaseInfo = caseBaseInfoService.getById(mainId);
                Optional<CaseTortoiseFraudPush> fraudPushOptional = caseTortoiseFraudPushService.list(
                        Wrappers.<CaseTortoiseFraudPush>lambdaQuery()
                            .eq(CaseTortoiseFraudPush::getApplyNo,caseBaseInfo.getApplyNo())
                            .eq(CaseTortoiseFraudPush::getPushResult,AfsEnumUtil.desc(GwtTortoiseFraudPushResult.PUSHED))
                            .orderByDesc(CaseTortoiseFraudPush::getCreateTime)
                ).stream().findFirst();
                if(fraudPushOptional.isPresent()){
                    CaseTortoiseFraudPush fraudPush = fraudPushOptional.get();
                    TortoiseFraudPushData pushData = TortoiseFraudPushData.builder()
                            .dealerJoin(fraudPush.getDealerJoin())
                            .fraudType(fraudPush.getFraudType())
                            .fraudDetailMessage(fraudPush.getDetailMessage())
                            .pushUser(fraudPush.getOperateStaffName())
                            .build();
                    pushData.setMainId(mainId);
                    pushData.setSerialNumber(fraudPush.getId().toString());
                    pushData.setApplyNo(caseBaseInfo.getApplyNo());
                    pushData.setCallStep(fraudPush.getCallStep());
                    queryBean = pushData;
                }
            }
            queryBean.setScene(sceneEnum);
        }
        return queryBean;
    }
}
